feat(pptx): layout-instantiation hardening, diagram primitive, crop/radius + non-16:9 diagnostics#90
Merged
karthikmudunuri merged 3 commits intoJun 10, 2026
Conversation
…radius + non-16:9 diagnostics P1 — layout instantiation hardening: - Fix: layout-instantiated slides now inherit their layout background (no spurious <a:noFill/> overriding master/theme chrome). - Add DeckLayout.type + summarizeLayouts()/placeholderKey() for model-facing layout selection. P2 — non-16:9 chrome diagnostics: - SerializeOptions.onWarning surfaces a machine-readable "chrome-skipped" warning when a source template's size is unreadable; 16:10 round-trip test. P3 — first-class DiagramElement: - process/timeline/funnel/matrix/cycle/list modelled as labelled nodes; shared layoutDiagram feeds renderer + a grouped, editable <p:grpSp> writer. P4 — round-trip fidelity: - Image crop (<a:srcRect>) + corner radius (roundRect) now round-trip via a dedicated <p:pic> synth writer + radius parse. - Text-run letter-case (cap) re-applied on export (pptxgenjs has no cap option).
- summarizeLayouts(deck, { compact, dedupe }) for 85-layout templates: compact
drops geometry; dedupe collapses same role+fillable into aliases.
- sourceLayoutId resolves from deck.layouts OR ppt/slideLayouts/<id>.xml in the
source archive; layout-unresolved onWarning when neither resolves.
- chrome-skipped warning carries sourceAspect/outputAspect.
- README: author-a-slide contract, non-text slot recipe, layoutDiagram
server-render recipe + DOM-free guarantee.
- Tests: compact/dedupe, filled-text round-trip, host-authored image slot,
by-convention + unresolved layout resolution, multi-master instantiation,
enriched chrome-skipped payload.
summarizeLayouts({dedupe}) keyed off role + text-fillable keys only, so a
chart-bearing layout could collapse into an otherwise-identical text-only twin
and the host would lose the data-visual variant. Key off the full placeholder
inventory (category:key over text AND chart/picture/table slots) instead.
Dedupe now runs on full summaries before compacting, so compact+dedupe is safe.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Forward-looking package work for host deck generation (Plan B, P1–P4). Each item ships with a changeset; the suite is green (141 passed / 9 skipped),
tscclean,build:libsucceeds.P1 — finish layout instantiation (
addSlideFromLayout) ⭐transparentbackground was serializing an explicit<p:bg><a:noFill/>, which overrides layout/master/theme inheritance in PowerPoint — so instantiated slides rendered with no background. They now stay<p:bg>-less and paint from theirsourceLayoutIdlayout's chrome.DeckLayout.typecarries the raw OOXML<p:sldLayout type>; newsummarizeLayouts(deck)returns a compact, model-context-friendly menu (friendlyrole, fillablefillskeys, per-placeholder kind/category/geometry);placeholderKey(ph)exposes a slot'sfillskey.P2 — non-16:9 chrome diagnostics
Sizing for 4:3 / 16:10 / custom already drives the output
sldSz(#86). This adds the machine-readable signal the plan asked for:serializeDeck(deck, { source, onWarning })emits a structuredSerializeWarning("chrome-skipped"when a source size is unreadable and chrome falls back to generic;"element-write-failed"per element) instead of only a console line.P3 — first-class diagram primitive
New
DiagramElement(process/timeline/funnel/matrix/cycle/list) models labellednodes. A single sharedlayoutDiagramfeeds both the renderer (DiagramView) and the writer (synthesiseDiagram), so preview and export can't drift. Exports to a single labelled<p:grpSp>of real shapes + connectors — grouped and editable in PowerPoint instead of anonymous loose shapes. Round-trips to an editableGroupElementcarrying the labels.P4 — round-trip fidelity
crop+radius:cropwas parsed on import but dropped on export, andradiuswas unhandled. Images carrying either now route through a dedicated<p:pic>synth writer (emitting<a:srcRect>+roundRect) — bypassing pptxgenjs, whose cover/contain sizing emits its own conflicting<a:srcRect>— andradiusis parsed back. Plain images keep the old path.cap: all-caps / small-caps (<a:rPr cap>) was parsed but dropped (pptxgenjs has nocapoption); now re-applied per run in post-process.Deliberately not built
renderDeckToImages(headless PNG export) — needs a DOM/canvas + ECharts runtime, so it can't be a pure package function without pulling a browser dep into the lib.buildChartOptionand the newlayoutDiagramalready let a host render server-side without re-implementing the package's logic; recommend it stay host-side or ship as a separate optional render entrypoint.Tests
New / extended: instantiable-layouts (chrome round-trip + summarizeLayouts), non-16:9 (16:10 + chrome-skipped warning), diagram (layout unit + serializer + renderer smoke), crop-radius-runs (image crop/radius + rich-run + cap round-trip).